package com.jeebey.mybatis.interceptor;

import java.util.List;
import java.util.Properties;

import org.apache.ibatis.executor.CachingExecutor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.SimpleExecutor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import com.jeebey.mybatis.utils.MappedStatmentUtil;

/**参数加强插件
 * @since 1.0
 * @author <a href="mailto:84961426@qq.com">JuST4iT</a>
 * @version $Id: ParameterInterceptor.java Feb 18, 2016 6:05:43 PM $
 */

@Intercepts({
	@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,RowBounds.class, ResultHandler.class }),
	@Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class ParameterInterceptor implements Interceptor {

	public Object intercept(Invocation invocation) throws Throwable {
		Object targetObject=invocation.getTarget();
		MetaObject executorMetaObject = MetaObject.forObject(targetObject, new DefaultObjectFactory(),new DefaultObjectWrapperFactory(),new DefaultReflectorFactory());
		while (executorMetaObject.hasGetter("h")||executorMetaObject.hasGetter("target")) {
			Object _hTargetObj=executorMetaObject.hasGetter("h")?executorMetaObject.getValue("h"):null;
			Object _tTargetObj=executorMetaObject.hasGetter("target")?executorMetaObject.getValue("target"):null;
			targetObject = _hTargetObj!=null?_hTargetObj:_tTargetObj;
			executorMetaObject = MetaObject.forObject(targetObject, new DefaultObjectFactory(),new DefaultObjectWrapperFactory(),new DefaultReflectorFactory());
		}
		
		if (targetObject instanceof CachingExecutor|| targetObject instanceof SimpleExecutor) {
			final MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
			final Object parameterObject = invocation.getArgs()[1];
			final String sourceSql = mappedStatement.getBoundSql(parameterObject).getSql();
			
			if(!sourceSql.contains("$[")&&!sourceSql.contains("]")){
				return invocation.proceed();
			}
			
			List<ParameterMapping> parameterMappings=mappedStatement.getBoundSql(parameterObject).getParameterMappings();
			invocation.getArgs()[0] =MappedStatmentUtil.createParameterMappedStatement(mappedStatement,sourceSql,parameterObject,parameterMappings);
		}
		return invocation.proceed();
	}

	public Object plugin(Object object) {
		return Plugin.wrap(object, this);
	}

	public void setProperties(Properties properties) {
	}
}
